home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / em-xmkit.zip / ROLODEX.C < prev    next >
Text File  |  1989-11-20  |  47KB  |  990 lines

  1. /**********************************************************************/
  2. /*                                                                    */
  3. /*     Module:      R O L O D E X                                     */
  4. /*                                                                    */
  5. /*                                                                    */
  6. /*        The intent of this example program is to show how to store  */
  7. /*     data in expanded memory using the C Memory Manager -- MEMLIB.  */
  8. /*     This program simulates a rolodex using a doubly-linked-list    */
  9. /*     data structure.  The user can insert, delete, edit, and save   */
  10. /*     the rolodex data to a file.  This example shows what           */
  11. /*     developers need to do in order to manipulate expanded memory   */
  12. /*     in their own application by using MEMLIB routines.             */
  13. /*                                                                    */
  14. /*        If you take a look at the NODE data structure, you'll       */
  15. /*     notice that there aren't any pointers as you would             */
  16. /*     traditionally see in such a structure. We use token            */
  17. /*     identifiers for the blocks of expanded memory they're          */
  18. /*     associated with.  Since we'll be mapping these blocks in and   */
  19. /*     out of expanded memory, the tokens will be exactly what we     */
  20. /*     need to keep track of them.                                    */
  21. /*                                                                    */
  22. /**********************************************************************/
  23.  
  24. /**********************************************************************/
  25. /* Rolodex.h contains all of the other headers, constants, and global */
  26. /* variables needed for this program.  Rolodex.h also contains        */
  27. /* housekeeping functions for the rolodex:  redrawing the screen,     */
  28. /* menu choices, cursor control, etc.                                 */
  29. /**********************************************************************/
  30.  
  31. #include "rolodex.h"
  32.  
  33. /*$PAGE*/
  34. /**********************************************************************/
  35. /*                                                                    */
  36. /*     Name:  void abort (status)                                     */
  37. /*            unsigned int status;                                    */
  38. /*                                                                    */
  39. /*     Description:                                                   */
  40. /*        Aborts the program with an error message.  This function    */
  41. /*     makes use of MEMLIB function 12 -- effreeall().  effreeall()   */
  42. /*     frees all pages, blocks, and handles associated with this      */
  43. /*     application.  It is imperative that you release all the        */
  44. /*     expanded memory you've allocated before exiting, so that other */
  45. /*     applications can use this memory.  If you don't, you'll have   */
  46. /*     to reboot to recover the lost memory.  Notice also that a call */
  47. /*     to effreeall() checks the EMM status.  In case that call       */
  48. /*     fails,  you'll get an error condtion back to let you know the  */
  49. /*     memory was not freed.                                          */
  50. /*                                                                    */
  51. /*     Parameters:                                                    */
  52. /*        input  status    The error condition of EMM                 */
  53. /*                                                                    */
  54. /*     Results returned: None                                         */
  55. /*                                                                    */
  56. /*     Calls:  effreeall()                                            */
  57. /*                                                                    */
  58. /*     Called by: edit_fields()                                       */
  59. /*                main_menu()                                         */
  60. /*                main()                                              */
  61. /*                                                                    */
  62. /*     Globals referenced/modified: None                              */
  63. /*                                                                    */
  64. /**********************************************************************/
  65.  
  66. void abort (status)
  67. unsigned int status;
  68.  
  69.    {
  70.    unsigned int free_status;
  71.  
  72.    /***********************************************************/
  73.    /* Print the error and free all allocated expanded memory. */
  74.    /***********************************************************/
  75.  
  76.    printf ("ERROR ERROR ERROR %X \n",status);
  77.  
  78.    free_status = effreeall();
  79.  
  80.    /******************************************************/
  81.    /* Make sure we didn't get an error from effreeall(). */
  82.    /******************************************************/
  83.  
  84.    if (free_status != PASSED)
  85.       printf ("ERROR %X from effreeall()\n");
  86.    exit (1);
  87.  
  88.    }  /** end abort **/
  89.  
  90.  
  91. /*$PAGE*/
  92. /**********************************************************************/
  93. /*                                                                    */
  94. /*     Name: unsigned int initialize_list (void)                      */
  95. /*                                                                    */
  96. /*     Description:                                                   */
  97. /*        This is just the initialization process for the rolodex     */
  98. /*     program.  It allocates space from expanded memory for the      */
  99. /*     first rolodex entry -- the logo screen.  This is actually the  */
  100. /*     "dummy" node for the doubley-linked-list data structure that   */
  101. /*     holds all the rolodex information.  If you take a look at the  */
  102. /*     NODE data structure, you'll notice we don't use traditional    */
  103. /*     pointers in the structure.  We use token identifiers to keep   */
  104. /*     track of the blocks mapped in and out of expanded memory.      */
  105. /*     We then map this "dummy" node in, set its "pointers," and read */
  106. /*     in the data file "rolodex.dat."  As we read in the rolodex     */
  107. /*     data for each "card," expanded memory is allocated, mapped in, */
  108. /*     and the link-list is updated.  See insert_node() for more      */
  109. /*     information on allocating and mapping.                         */
  110. /*                                                                    */
  111. /*     Parameters: None                                               */
  112. /*                                                                    */
  113. /*     Results returned:                                              */
  114. /*        Condition of EMM. PASSED or type of error encountered.      */
  115. /*                                                                    */
  116. /*     Calls:  efmalloc()                                             */
  117. /*             set1eptr()                                             */
  118. /*                                                                    */
  119. /*     Called by:  main()                                             */
  120. /*                                                                    */
  121. /*     Globals referenced/modified:  current_view_node                */
  122. /*                                   size_table                       */
  123. /*                                   offset_table                     */
  124. /*                                   start_of_list                    */
  125. /*                                                                    */
  126. /**********************************************************************/
  127.  
  128. unsigned int initialize_list (void)
  129.  
  130.    {
  131.    FILE         *fp;                  /* file handle                      */
  132.    int          prev_node;            /* the node before the current node */
  133.    int          this_node;            /* the current node                 */
  134.    int          i, j;                 /* loops                            */
  135.    NODE         far *prev_ptr;        /* pointer to the previous node     */
  136.    NODE         far *this_ptr;        /* pointer to this node             */
  137.    char         buff[TOTAL_SIZE + 1]; /* buffer to read from file         */
  138.    unsigned int status;               /* error tracking                   */
  139.  
  140.    /**********************************************************/
  141.    /* Set up offset table (offsets into NODE data structure) */
  142.    /**********************************************************/
  143.  
  144.    offset_table[0] = 0;
  145.    for (i = 1; i < NUMBER_OF_OPTIONS; i++)
  146.        offset_table[i] = offset_table[i-1] + size_table[i-1];
  147.  
  148.    /*******************************************************************/
  149.    /* Allocate a dummy node for the start of the list (start_of_list).*/
  150.    /* Rolodex will display a logo when it views this node.            */
  151.    /*******************************************************************/
  152.  
  153.    status = efmalloc (sizeof(NODE), &start_of_list);
  154.  
  155.    /*********************************/
  156.    /* Get access to this dummy node */
  157.    /*********************************/
  158.  
  159.    if (status == PASSED)
  160.        status = set1eptr (start_of_list, &prev_ptr);
  161.  
  162.    /****************************************************************/
  163.    /* Set the pointers on this node to point to the node itself.   */
  164.    /* This list is a circular-linked list.                         */
  165.    /****************************************************************/
  166.  
  167.    if (status == PASSED)
  168.        {
  169.        prev_ptr->next_node = start_of_list;
  170.        prev_ptr->prev_node = start_of_list;
  171.  
  172.        /****************************/
  173.        /* Prepare for reading loop */
  174.        /****************************/
  175.  
  176.        prev_node = start_of_list;
  177.        current_view_node = start_of_list; 
  178.  
  179.        /********************************/
  180.        /* Try to open file for reading */
  181.        /********************************/
  182.  
  183.        fp = fopen ("rolodex.dat", "r");
  184.  
  185.        if (fp != NULL)
  186.            {
  187.        
  188.            /*********************************************/
  189.            /* While a full data buffer has been read... */
  190.            /*********************************************/
  191.  
  192.            while ((fgets (buff, TOTAL_SIZE + 1, fp) != NULL)
  193.                    && (status == PASSED))
  194.                {
  195.  
  196.                if (strlen (buff) >= TOTAL_SIZE)
  197.                    {                      
  198.  
  199.                    /********************************************/
  200.                    /* Allocate space for this node and set the */
  201.                    /* previous node to point to it.            */
  202.                    /********************************************/
  203.  
  204.                    status = efmalloc (sizeof(NODE), &this_node);
  205.                    prev_ptr->next_node = this_node;
  206.  
  207.                    /***************************/
  208.                    /* Get access to this node */
  209.                    /***************************/
  210.  
  211.                    if (status == PASSED)
  212.                        status = set1eptr (this_node, &this_ptr);
  213.  
  214.                    /******************************************************/
  215.                    /* Copy buffer into node, set pointers on the node,   */
  216.                    /* and update variables for stepping through the list.*/
  217.                    /******************************************************/
  218.  
  219.                    if (status == PASSED)
  220.                        {
  221.                        for (i = 0; i < TOTAL_SIZE; i++)
  222.                            this_ptr->data[i] = buff[i];
  223.  
  224.                        this_ptr->prev_node = prev_node;
  225.                        this_ptr->next_node = start_of_list;
  226.  
  227.                        prev_node = this_node;
  228.                        prev_ptr = this_ptr;
  229.                        }
  230.                    } /** end if fgets(...) **/
  231.                }
  232.  
  233.            /************************************************************/
  234.            /* Connect the start to the end.  (This is a circular list.)*/
  235.            /************************************************************/
  236.  
  237.            status = set1eptr (start_of_list, &this_ptr);
  238.            if (status == PASSED)
  239.                this_ptr->prev_node = prev_node;
  240.  
  241.            fclose (fp);
  242.            }  /** end if fp != NULL **/
  243.        }
  244.  
  245.    return (status);
  246.    }
  247.  
  248. /*$PAGE*/
  249. /**********************************************************************/
  250. /*                                                                    */
  251. /*     Name: unsigned int save_list (void)                            */
  252. /*                                                                    */
  253. /*     Description:                                                   */
  254. /*        Saves the current contents of the list to a file called     */
  255. /*     "rolodex.dat".  As save_list goes through the list, it gains   */
  256. /*     access to each node we want to save by mapping in the block    */
  257. /*     associated with the node.                                      */
  258. /*                                                                    */
  259. /*     Parameters:  None                                              */
  260. /*                                                                    */
  261. /*     Results returned:                                              */
  262. /*        Condition of EMM.  PASSED or type of error encountered.     */
  263. /*                                                                    */
  264. /*     Calls:  set1eptr()                                             */
  265. /*                                                                    */
  266. /*     Called by:  main_menu()                                        */
  267. /*                                                                    */
  268. /*     Globals referenced/modified:  start_of_list                    */
  269. /*                                                                    */
  270. /**********************************************************************/
  271.  
  272. unsigned int save_list (void)
  273.  
  274.    {
  275.    FILE         *fp;                  /* file handle                   */
  276.    int          this_node;            /* current node to save          */
  277.    int          i;                    /* looping                       */
  278.    NODE far     *this_ptr;            /* pointer to current node       */
  279.    char         buff[TOTAL_SIZE + 1]; /* local buffer to write to file */
  280.    unsigned int status;               /* error tracking                */
  281.  
  282.    /*******************************/
  283.    /* Get access to start of list */
  284.    /*******************************/
  285.  
  286.    status = set1eptr (start_of_list, &this_ptr);
  287.  
  288.    /*************************************************************************/
  289.    /* Attempt to open file; if attempt is unsuccessful, set status to failed*/
  290.    /*************************************************************************/
  291.  
  292.    fp = fopen("rolodex.dat", "w");
  293.  
  294.    if ((status == PASSED) && (fp != NULL))
  295.        {
  296.  
  297.        /*********************************************************/
  298.        /* set current node to first node AFTER dummy start node */
  299.        /*********************************************************/
  300.  
  301.        this_node = this_ptr->next_node;
  302.  
  303.        /**************************************************************/
  304.        /* While we haven't circled all the way back to the start ... */
  305.        /**************************************************************/
  306.  
  307.        while ((this_node != start_of_list) && (status == PASSED))
  308.            {
  309.  
  310.            /***************************/
  311.            /* Get access to this node */
  312.            /***************************/
  313.  
  314.            status = set1eptr (this_node, &this_ptr);
  315.            if (status == PASSED)
  316.                {
  317.  
  318.                /**************************************************/
  319.                /* Set local buffer, write it to file, and update */
  320.                /* current node to step thru list.                */
  321.                /**************************************************/
  322.  
  323.                for (i = 0; i < TOTAL_SIZE; i++)
  324.                   buff[i] = this_ptr->data[i];
  325.                buff[TOTAL_SIZE] = '\0';
  326.  
  327.                fprintf (fp, "%s\n", buff);
  328.  
  329.                this_node = this_ptr->next_node;
  330.                }
  331.            } /** end while **/
  332.  
  333.        fclose (fp);
  334.        }  /** end if status... **/
  335.  
  336.    return (status);
  337.  
  338.    }  /** end save_list **/
  339.  
  340. /*$PAGE*/
  341. /**********************************************************************/
  342. /*                                                                    */
  343. /*     Name: unsigned int display_total_exp_mem (void)                */
  344. /*                                                                    */
  345. /*     Description:                                                   */
  346. /*        Displays the total amount of free expanded memory on the    */
  347. /*     rolodex main screen.  We just call MEMLIB function 1 --        */
  348. /*     ememavl() to get the total amount of free expanded memory      */
  349. /*     available.                                                     */
  350. /*                                                                    */
  351. /*     Parameters:  None                                              */
  352. /*                                                                    */
  353. /*     Results returned:                                              */
  354. /*        Condition of EMM.  PASSED or type of error encountered.     */
  355. /*                                                                    */
  356. /*     Calls:  ememavl()                                              */
  357. /*                                                                    */
  358. /*     Called by:  show_node()                                        */
  359. /*                                                                    */
  360. /*     Globals referenced/modified:  None                             */
  361. /*                                                                    */
  362. /**********************************************************************/
  363.  
  364. unsigned int display_total_exp_mem()
  365.    {
  366.    unsigned int status;
  367.    unsigned long  size;
  368.  
  369.    /***************************************************************/
  370.    /* Get the amount of expanded memory available and display it. */
  371.    /***************************************************************/
  372.  
  373.    status = ememavl (&size);
  374.    if (status == PASSED)
  375.        { 
  376.        _settextposition (TOTAL_EXP_MEM_ROW, TOTAL_EXP_MEM_COL);
  377.        printf ("Expanded Memory Available: %8lu   ", size);
  378.        }
  379.    return (status);
  380.    }
  381.  
  382. /*$PAGE*/
  383. /**********************************************************************/
  384. /*                                                                    */
  385. /*     Name: unsigned int display_max_block (void)                    */
  386. /*                                                                    */
  387. /*     Description:                                                   */
  388. /*        Displays the largest allocatable block on the main rolodex  */
  389. /*     screen.  We just call MEMLIB function 2 --  ememmax() to get   */
  390. /*     the largest block available.                                   */
  391. /*                                                                    */
  392. /*     Parameters:  None                                              */
  393. /*                                                                    */
  394. /*     Results returned:                                              */
  395. /*        Condition of EMM.  PASSED or type of error encountered.     */
  396. /*                                                                    */
  397. /*     Calls:  ememmax()                                              */
  398. /*                                                                    */
  399. /*     Called by:  show_node()                                        */
  400. /*                                                                    */
  401. /*     Globals referenced/modified:  None                             */
  402. /*                                                                    */
  403. /**********************************************************************/
  404.  
  405. unsigned int display_max_block()
  406.    {
  407.    unsigned int status;
  408.    unsigned int size;
  409.  
  410.    /*****************************************************/
  411.    /* Get the largest allocatable block and display it. */
  412.    /*****************************************************/
  413.  
  414.    status = ememmax (&size);
  415.    if (status == PASSED)
  416.        {
  417.        _settextposition (MAX_BLOCK_ROW, MAX_BLOCK_COL);
  418.        printf ("Maximum Block Size: %5u", size);
  419.        }
  420.    return (status);
  421.    }
  422.  
  423. /*$PAGE*/
  424. /**********************************************************************/
  425. /*                                                                    */
  426. /*     Name: unsigned int display_block_size (block)                  */
  427. /*           int block;                                               */
  428. /*                                                                    */
  429. /*     Description:                                                   */
  430. /*        Displays the size (in bytes) of the block of expanded       */
  431. /*     memory passed to it.  (In this context it is the node being    */
  432. /*     displayed on the screen).  We just call MEMLIB function 4 --   */
  433. /*     emsize() to get the size of the block by passing the token     */
  434. /*     identifier of the block we want.                               */
  435. /*                                                                    */
  436. /*     Parameters:  None                                              */
  437. /*                                                                    */
  438. /*     Results returned:                                              */
  439. /*        Condition of EMM.  PASSED or type of error encountered.     */
  440. /*                                                                    */
  441. /*     Calls:  emsize()                                               */
  442. /*                                                                    */
  443. /*     Called by:  show_node()                                        */
  444. /*                                                                    */
  445. /*     Globals referenced/modified:  None                             */
  446. /*                                                                    */
  447. /**********************************************************************/
  448.  
  449. unsigned int display_block_size (block)
  450. int block;
  451.    {
  452.    unsigned int status;
  453.    unsigned int   size;
  454.  
  455.    /*****************************************************/
  456.    /* Get the size of the current block and display it. */
  457.    /*****************************************************/
  458.  
  459.    status = emsize (block, &size);
  460.    if (status == PASSED)
  461.        {
  462.        _settextposition (BLOCK_SIZE_ROW, BLOCK_SIZE_COL);
  463.        printf ("Size of Node: %5u", size);
  464.        }
  465.    return (status);
  466.    }
  467.  
  468. /*$PAGE*/
  469. /**********************************************************************/
  470. /*                                                                    */
  471. /*     Name:  unsigned int show_node (node_to_show)                   */
  472. /*            int node_to_show;                                       */
  473. /*                                                                    */
  474. /*     Description:                                                   */
  475. /*        Draws the requested node on screen; includes all of its     */
  476. /*     fields and the size of the expanded memory block it's using.   */
  477. /*                                                                    */
  478. /*     Parameters:                                                    */
  479. /*        input node_to_show    "pointer" to the node to show         */
  480. /*                                                                    */
  481. /*     Results returned:                                              */
  482. /*        Condition of EMM.  PASSED or type of error encountered.     */
  483. /*                                                                    */
  484. /*     Calls: set1eptr()                                              */
  485. /*                                                                    */
  486. /*     Called by:  edit_fields()                                      */
  487. /*                 main_menu()                                        */
  488. /*                                                                    */
  489. /*     Globals referenced/modified:  option_list                      */
  490. /*                                   size_table                       */
  491. /*                                   offset_table                     */
  492. /*                                   start_of_list                    */
  493. /*                                                                    */
  494. /**********************************************************************/
  495.  
  496. unsigned int show_node (node_to_show)
  497. int node_to_show;
  498.  
  499.    {
  500.    int          i, j;                     /* looping                      */
  501.    short        row;                      /* row to output text on        */
  502.    short        col;                      /* column to output text on     */
  503.    NODE far     *ptr;                     /* pointer to the node          */
  504.    char         buff[MAX_DATA_SIZE + 1];  /* local buffer for each string */
  505.    unsigned int status;                   /* error tracking               */
  506.    unsigned int size;                     /* size of this node            */
  507.  
  508.    /**********************************/
  509.    /* Get access to the node to show */
  510.    /**********************************/
  511.  
  512.    status = set1eptr (node_to_show, &ptr);
  513.  
  514.    if (status == PASSED)
  515.        if (node_to_show == start_of_list)
  516.            {
  517.  
  518.            /**************************************************/
  519.            /* We're at the start of the list - draw the logo */
  520.            /**************************************************/
  521.  
  522.            clear_rolodex();
  523.            draw_logo();
  524.            status = display_total_exp_mem();
  525.            if (status == PASSED)
  526.                status = display_max_block();
  527.            }
  528.  
  529.        else
  530.            {
  531.  
  532.            /************************************************/
  533.            /* This is real node (NOT the dummy start node) */
  534.            /************************************************/
  535.  
  536.            clear_rolodex();
  537.            for (i = 0; i < NUMBER_OF_OPTIONS; i++)
  538.                {
  539.  
  540.                /*****************************************************/
  541.                /* For each option,                                  */
  542.                /*   - set the row and column                        */
  543.                /*   - write the option title to the screen          */
  544.                /*   - copy node data to local buffer                */
  545.                /*   - write node data to the screen                 */
  546.                /*****************************************************/
  547.  
  548.                row = option_list[i].row;
  549.                col = option_list[i].column - option_list[i].title_length;
  550.  
  551.                _settextposition(row, col);
  552.                _outtext(option_list[i].title);
  553.  
  554.                for (j = 0; j < size_table[i]; j++)
  555.                    buff[j] = ptr->data[j + offset_table[i]];
  556.                buff[j] = '\0';
  557.  
  558.                _outtext(buff);
  559.  
  560.                }  /** end for ... **/
  561.  
  562.            status = display_block_size (node_to_show);
  563.  
  564.            } /** end else **/
  565.  
  566.    return (status);
  567.    } /** end show_node **/
  568.  
  569. /*$PAGE*/
  570. /**********************************************************************/
  571. /*                                                                    */
  572. /*     Name: unsigned int insert_node (void)                          */
  573. /*                                                                    */
  574. /*     Description:                                                   */
  575. /*        Inserts a new node in the linked-list.  First, we allocate  */
  576. /*     the amount of expanded memory required for a node by calling   */
  577. /*     MEMLIB function 3 -- efmalloc().  We pass the size we want     */
  578. /*     and get a token identifier for that particuliar block.  Each   */
  579. /*     token is unique to that block of expanded memory.              */
  580. /*                                                                    */
  581. /*         Next, we use MEMLIB function 7, set1eptr(), to gain access */
  582. /*     to this block (map it in from expanded memory into conventional*/
  583. /*     and get a pointer to it).  We give set1eptr() the token        */
  584. /*     identifier of the block we want access to (in this case        */
  585. /*     "this_node"), and this function does the mapping and returns a */
  586. /*     pointer to this block of memory.                               */
  587. /*                                                                    */
  588. /*         We then allow a user to enter the data for this node by    */
  589. /*     calling edit_node().  Once the user accepts the data, the new  */
  590. /*     node is inserted into the sorted-by-last-name linked-list.     */
  591. /*     list.  We use MEMLIB function 8 -- set2eptrs() -- to do this.  */
  592. /*     This function will map in two blocks and assign them two       */
  593. /*     separate pointers.  This allows access to two blocks at the    */
  594. /*     same time.  Finally, we insert the new node between the two    */
  595. /*     nodes we just mapped in.                                       */
  596. /*                                                                    */
  597. /*     Parameters: None                                               */
  598. /*                                                                    */
  599. /*     Results returned:                                              */
  600. /*        Condition of EMM. PASSED or type of error encountered.      */
  601. /*                                                                    */
  602. /*     Calls:  efmalloc()                                             */
  603. /*             set1eptr()                                             */
  604. /*             edit_fields()                                          */
  605. /*             set2eptrs()                                            */
  606. /*             compare_last_names()                                   */
  607. /*                                                                    */
  608. /*     Called by:  main_menu()                                        */
  609. /*                                                                    */
  610. /*     Globals referenced/modified:  start_of_list                    */
  611. /*                                   current_view_node                */
  612. /*                                                                    */
  613. /**********************************************************************/
  614.  
  615. unsigned int insert_node (void)
  616.  
  617.    {
  618.    unsigned int status;        /* Error tracking                      */
  619.    unsigned int edit_status;   /* accept/exit picked from edit_node() */
  620.    int          this_node;     /* "Pointer" to the current node       */
  621.    int          temp_node;     /* "Pointer" to node to insert         */
  622.    int          i;             /* Loop                                */
  623.    NODE far     *this_ptr;     /* Pointer to this_node                */
  624.    NODE far     *temp_ptr;     /* Pointer to temp_node                */
  625.    static char  *title =       /* Title line for edit_fields call     */
  626.       "            INSERT A NEW ENTRY                   ";
  627.  
  628.    /******************************************************/
  629.    /* Allocate space for a new node and get access to it */
  630.    /******************************************************/
  631.  
  632.    status = efmalloc (sizeof(NODE), &this_node);
  633.    if (status == PASSED)
  634.        status = set1eptr (this_node, &this_ptr);
  635.  
  636.    /************************************************************/
  637.    /* Set data to '_' for display and then call edit_fields to */
  638.    /* insert new data in the node.                             */
  639.    /************************************************************/
  640.  
  641.    if (status == PASSED)
  642.        {
  643.        for (i = 0; i < TOTAL_SIZE; i++)
  644.            this_ptr->data[i] = '_';
  645.        edit_status = edit_fields (title, this_node);
  646.        }
  647.  
  648.    /************************************************************/
  649.    /* If the user chose "accept" (from edit_fields), insert    */
  650.    /* this node into the list alphabetically.                  */
  651.    /************************************************************/
  652.  
  653.    if ((status == PASSED) && (edit_status == ACCEPT))
  654.        {
  655.  
  656.        /***************************************/
  657.        /* Get access to the start of the list */
  658.        /***************************************/
  659.  
  660.        status = set1eptr (start_of_list, &this_ptr);
  661.  
  662.        /***********************************************************/
  663.        /* Get access to the next node in the list (temp_node) and */
  664.        /* the node to be inserted (this_node).                    */
  665.        /***********************************************************/
  666.  
  667.        if (status == PASSED)
  668.            {
  669.            temp_node = this_ptr->next_node;
  670.            status = set2eptrs (temp_node, this_node, &temp_ptr, &this_ptr);
  671.            }
  672.  
  673.        /***************************************************************/
  674.        /* Step through the list as long as we haven't circled back to */
  675.        /* the start and the last name of the node to insert is later  */
  676.        /* in the alphabet than the name of the current node.          */
  677.        /***************************************************************/
  678.  
  679.        while ((temp_node != start_of_list) &&
  680.               (compare_last_names (this_ptr, temp_ptr) > 0) &&
  681.               (status == PASSED))
  682.            {
  683.  
  684.            /**********************************************************/
  685.            /* Step to next node in list and get access to it and the */
  686.            /* node we're inserting.                                  */
  687.            /**********************************************************/
  688.  
  689.            temp_node = temp_ptr->next_node;
  690.            status = set2eptrs (temp_node, this_node, &temp_ptr, &this_ptr);
  691.  
  692.            }
  693.  
  694.        if (status==PASSED)
  695.            {
  696.  
  697.            /*********************************************************/
  698.            /* temp_node is now pointing at the node we want to      */
  699.            /* insert in front of.  (If we're at the end of the list,*/
  700.            /* temp_node points at start_of_list.)  Set the pointers */
  701.            /* on the new node to point to temp_node and the node    */
  702.            /* before temp_node.  Set the prev_node pointer of temp_ */
  703.            /* node to point to the new node.  Set the next_node     */
  704.            /* pointer of the node before temp_node to point to the  */
  705.            /* new node.                                             */
  706.            /*********************************************************/
  707.  
  708.            this_ptr->next_node = temp_node;
  709.            this_ptr->prev_node = temp_ptr->prev_node;
  710.  
  711.            temp_ptr->prev_node = this_node;
  712.  
  713.            /* Get access to the previous node */
  714.  
  715.            status = set1eptr (this_ptr->prev_node, &temp_ptr);
  716.            temp_ptr->next_node = this_node;
  717.  
  718.            /* Set the current view node to the node we inserted */
  719.  
  720.            current_view_node = this_node;
  721.  
  722.            } /** end if status **/
  723.  
  724.        } /** end if status **/
  725.    else
  726.        /******************/
  727.        /* Free this node */
  728.        /******************/
  729.  
  730.        effree (this_node);
  731.  
  732.    return (status);
  733.  
  734.    } /** end insert_node **/
  735.  
  736. /*$PAGE*/
  737. /**********************************************************************/
  738. /*                                                                    */
  739. /*     Name: unsigned int edit_node (void)                            */
  740. /*                                                                    */
  741. /*     Description:                                                   */
  742. /*        To edit an existing node.                                   */
  743. /*                                                                    */
  744. /*     Parameters: None                                               */
  745. /*                                                                    */
  746. /*     Results returned:                                              */
  747. /*        Condition of EMM.  PASSED or type of error encountered.     */
  748. /*                                                                    */
  749. /*     Calls:  efmalloc()                                             */
  750. /*             set2eptrs()                                            */
  751. /*             edit_fields()                                          */
  752. /*             effree()                                               */
  753. /*                                                                    */
  754. /*     Called by:  main_menu()                                        */
  755. /*                                                                    */
  756. /*     Globals referenced/modified:  start_of_list                    */
  757. /*                                   current_view_node                */
  758. /*                                                                    */
  759. /**********************************************************************/
  760.  
  761. unsigned int edit_node (void)
  762.  
  763.    {
  764.    unsigned int status;       /* Error tracking                     */
  765.    unsigned int edit_status;  /* Decide to keep/reject              */
  766.    int            temp_node;  /* "Pointer" to the node to edit      */
  767.    int            i;          /* Loop                               */
  768.    NODE far       *this_ptr;  /* pointer to current node            */
  769.    NODE far       *temp_ptr;  /* pointer to a temporary node        */
  770.    static char    *title =    /* Title line for call to edit_fields */
  771.        "               EDIT THIS ENTRY                   ";
  772.  
  773.    status = PASSED;
  774.  
  775.    /****************************************************/
  776.    /* Test for editable node (can't edit logo screen!) */
  777.    /****************************************************/
  778.  
  779.    if (current_view_node != start_of_list)
  780.        {
  781.  
  782.        /**************************************************************/
  783.        /* Allocate space for a temporary node (so that changes won't */
  784.        /* affect the real node if the user picks "exit.")            */
  785.        /**************************************************************/
  786.  
  787.        status = efmalloc (sizeof (NODE), &temp_node);
  788.  
  789.        /********************************************************/
  790.        /* Get access to the real node and the temporary node.  */
  791.        /********************************************************/
  792.  
  793.        if (status == PASSED)
  794.            status = set2eptrs (temp_node, current_view_node, &temp_ptr, &this_ptr);
  795.  
  796.        /******************************************************/
  797.        /* Copy the real node to the temporary one, and call  */
  798.        /* edit_fields to edit the temporary node.            */
  799.        /******************************************************/
  800.  
  801.        if (status == PASSED)
  802.            {
  803.            for (i = 0; i < TOTAL_SIZE; i++)
  804.                temp_ptr->data[i] = this_ptr->data[i];
  805.            edit_status = edit_fields (title, temp_node);
  806.            }
  807.  
  808.        /**************************************************************/
  809.        /* Get access to the real and temporary node (edit_fields     */
  810.        /* called set1eptr, so we no longer have access to both nodes)*/
  811.        /**************************************************************/
  812.  
  813.        if ((status == PASSED) & (edit_status == ACCEPT))
  814.            status = set2eptrs(temp_node, current_view_node, &temp_ptr, &this_ptr);
  815.  
  816.        /***************************************************************/
  817.        /* If the user chose "accept," copy the temporary node to the  */
  818.        /* real node and free the temporary node.                      */
  819.        /***************************************************************/
  820.  
  821.        if ((status == PASSED) & (edit_status == ACCEPT))
  822.            {
  823.            for (i = 0; i < TOTAL_SIZE; i++)
  824.                this_ptr->data[i] = temp_ptr->data[i];
  825.            status = effree (temp_node);
  826.            }
  827.  
  828.        } /** end if current_view_node... **/
  829.  
  830.    return(status);
  831.  
  832.    } /** end edit_node **/
  833.  
  834. /*$PAGE*/
  835. /**********************************************************************/
  836. /*                                                                    */
  837. /*     Name:  unsigned int delete_node (void)                         */
  838. /*                                                                    */
  839. /*     Description:                                                   */
  840. /*        Deletes the current view node from the list.  After mapping */
  841. /*     in the node the user wishes to delete, we map in the nodes     */
  842. /*     before and after it.  We then pass the token of the block to   */
  843. /*     delete to MEMLIB function 5, effree(), to deallocate it.       */
  844. /*                                                                    */
  845. /*     Parameters:  None                                              */
  846. /*                                                                    */
  847. /*     Results returned:                                              */
  848. /*        Condition of EMM.  PASSED or type of error encountered.     */
  849. /*                                                                    */
  850. /*     Calls:  set1eptr()                                             */
  851. /*             set2eptrs()                                            */
  852. /*             effree()                                               */
  853. /*                                                                    */
  854. /*     Called by:  main_menu()                                        */
  855. /*                                                                    */
  856. /*     Globals referenced/modified:  start_of_list                    */
  857. /*                                   current_view_node                */
  858. /*                                                                    */
  859. /**********************************************************************/
  860.  
  861. unsigned int delete_node (void)
  862.  
  863.    {
  864.    int          next_node;  /* "Pointer" to the next node in the list */
  865.    int          prev_node;  /* "Pointer" to the previous node         */
  866.    unsigned int status;     /* Error tracking                         */
  867.    NODE far     *next_ptr;  /* Pointer to next_node                   */
  868.    NODE far     *prev_ptr;  /* Pointer to previous node               */
  869.  
  870.    status = PASSED;
  871.  
  872.    /*********************************************************/
  873.    /* Check that we're not trying to delete the logo screen */
  874.    /*********************************************************/
  875.  
  876.    if (current_view_node != start_of_list)
  877.        {
  878.  
  879.        /**********************************/
  880.        /* Get access to the current node */
  881.        /**********************************/
  882.  
  883.        status = set1eptr (current_view_node, &next_ptr);
  884.  
  885.        if (status == PASSED)
  886.            {
  887.  
  888.            /********************************************************/
  889.            /* Get access to the nodes before and after the current */
  890.            /* node.                                                */
  891.            /********************************************************/
  892.  
  893.            next_node = next_ptr->next_node;
  894.            prev_node = next_ptr->prev_node;
  895.            status = set2eptrs (next_node, prev_node, &next_ptr, &prev_ptr);
  896.  
  897.            /*************************/
  898.            /* Free the current node */
  899.            /*************************/
  900.  
  901.            if (status == PASSED)
  902.                status = effree (current_view_node);
  903.            }
  904.  
  905.        /**********************************************************/
  906.        /* Chain the list around the gap left by the current node */
  907.        /**********************************************************/
  908.  
  909.        if (status == PASSED)
  910.            {
  911.            next_ptr->prev_node = prev_node;
  912.            prev_ptr->next_node = next_node;
  913.  
  914.            /* Set the current view node to the previous node */
  915.  
  916.            current_view_node = prev_node;
  917.            }
  918.  
  919.        } /** end if current_view_node... **/
  920.  
  921.    return (status);
  922.  
  923.    } /** end delete_node **/
  924.  
  925.  
  926. /*$PAGE*/
  927. /**********************************************************************/
  928. /*                                                                    */
  929. /*     Name: void main(void)                                          */
  930. /*                                                                    */
  931. /*     Description:                                                   */
  932. /*        The main body of the program.  Initializes the list, calls  */
  933. /*     main_menu (executive), and frees the nodes when finished.      */
  934. /*                                                                    */
  935. /*     Parameters:  None                                              */
  936. /*                                                                    */
  937. /*     Results returned:  None                                        */
  938. /*                                                                    */
  939. /*     Calls:  initialize_list()                                      */
  940. /*             draw_border()                                          */
  941. /*             main_menu()                                            */
  942. /*             effreeall()                                            */
  943. /*             abort()                                                */
  944. /*                                                                    */
  945. /*     Called by:  None                                               */
  946. /*                                                                    */
  947. /*     Globals referenced/modified:  None                             */
  948. /*                                                                    */
  949. /**********************************************************************/
  950.  
  951. void main()
  952.  
  953.    {
  954.    unsigned int status;
  955.  
  956.    /* Initialize the data */
  957.  
  958.    status = initialize_list();
  959.  
  960.    if (status != PASSED)
  961.        abort(status);
  962.  
  963.    else
  964.        {
  965.        /* Set up text window and clear it */
  966.  
  967.        _settextwindow (OUTSIDE_START_ROW, OUTSIDE_START_COL, OUTSIDE_END_ROW,
  968.                        OUTSIDE_END_COL);
  969.        _clearscreen (_GCLEARSCREEN);
  970.  
  971.        /* draw the rolodex border */
  972.  
  973.        draw_border();
  974.  
  975.        /* Call main executive routine */
  976.  
  977.        main_menu();
  978.  
  979.        /* Free up nodes used by the rolodex */
  980.  
  981.        status = effreeall();
  982.        _clearscreen (_GCLEARSCREEN);
  983.  
  984.        if (status != PASSED)
  985.            abort (status);
  986.        }
  987.  
  988.    }  /** end main **/
  989.  
  990.